package org.budo.graph.druid.spring.web.interceptor;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.budo.support.assertion.Assert;
import org.budo.support.slf4j.Slf4j;
import org.slf4j.Logger;
import org.springframework.web.servlet.ModelAndView;

import com.alibaba.druid.filter.stat.StatFilterContext;
import com.alibaba.druid.support.http.AbstractWebStatImpl;
import com.alibaba.druid.support.http.stat.WebAppStat;
import com.alibaba.druid.support.http.stat.WebAppStatManager;
import com.alibaba.druid.support.http.stat.WebSessionStat;
import com.alibaba.druid.util.DruidWebUtils;
import com.alibaba.druid.util.PatternMatcher;
import com.alibaba.druid.util.ServletPathMatcher;

import lombok.Setter;

/**
 * @author lmw
 */
@Setter
public class AbstractBudoGraphDruidSpringWebInterceptor extends AbstractWebStatImpl {
    private static final Logger log = Slf4j.getLogger();

    private Set<String> excludesPattern;

    protected PatternMatcher pathMatcher = new ServletPathMatcher();

    public void setExclusions(String exclusions) {
        log.info("#40 setExclusions, exclusions=" + exclusions);

        if (null != exclusions && !exclusions.trim().isEmpty()) {
            this.excludesPattern = new HashSet<String>(Arrays.asList(exclusions.split("\\s*,\\s*")));
        }
    }

    public boolean isExclusion(String requestURI) {
        if (this.excludesPattern == null || requestURI == null) {
            return false;
        }

        if (this.contextPath != null && requestURI.startsWith(this.contextPath)) {
            requestURI = requestURI.substring(this.contextPath.length());
            if (!requestURI.startsWith("/")) {
                requestURI = "/" + requestURI;
            }
        }

        for (String pattern : this.excludesPattern) {
            if (this.pathMatcher.matches(pattern, requestURI)) {
                return true;
            }
        }

        return false;
    }

    /**
     * @see com.alibaba.druid.support.http.WebStatFilter#init(javax.servlet.FilterConfig)
     * @see com.alibaba.druid.support.spring.mvc.StatHandlerInterceptor#getWebAppStat(HttpServletRequest)
     */
    public WebAppStat getWebAppStat(HttpServletRequest request) {
        if (null == super.webAppStat) {
            synchronized (AbstractBudoGraphDruidSpringWebInterceptor.class) {
                if (null == super.webAppStat) {
                    StatFilterContext.getInstance().addContextListener(this.statFilterContextListener);

                    ServletContext context = request.getSession().getServletContext();
                    this.contextPath = DruidWebUtils.getContextPath(context);
                    if (super.webAppStat == null) {
                        super.webAppStat = new WebAppStat(this.contextPath, this.sessionStatMaxCount);
                    }

                    WebAppStatManager.getInstance().addWebAppStatSet(this.webAppStat);
                }
            }
        }

        Assert.notNull(super.webAppStat, "this.webAppStat is null");
        return super.webAppStat;
    }

    /**
     * @see com.alibaba.druid.support.http.AbstractWebStatImpl#getSessionStat(HttpServletRequest)
     */
    public WebSessionStat getSessionStat(HttpServletRequest request) {
        if (!this.isSessionStatEnable()) {
            return null;
        }

        WebSessionStat sessionStat = null;
        String sessionId = this.getSessionId(request);
        if (sessionId != null) {
            sessionStat = this.getWebAppStat(request).getSessionStat(sessionId, true);
        }

        if (sessionStat != null) {
            long currentMillis = System.currentTimeMillis();

            String userAgent = request.getHeader("user-agent");

            if (sessionStat.getCreateTimeMillis() == -1L) {
                HttpSession session = request.getSession(false);

                if (session != null) {
                    sessionStat.setCreateTimeMillis(session.getCreationTime());
                } else {
                    sessionStat.setCreateTimeMillis(currentMillis);
                }

                this.getWebAppStat(request).computeUserAgent(userAgent);
                this.getWebAppStat(request).incrementSessionCount();
            }

            sessionStat.setUserAgent(userAgent);

            String remoteAddress = this.getRemoteAddress(request);
            sessionStat.addRemoteAddress(remoteAddress);
        }

        return sessionStat;
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        //
    }
}